package com.biz.es.util;

import com.alibaba.fastjson.*;
import com.biz.es.domain.*;
import lombok.extern.slf4j.*;
import org.apache.commons.lang3.*;
import org.elasticsearch.action.bulk.*;
import org.elasticsearch.action.delete.*;
import org.elasticsearch.action.get.*;
import org.elasticsearch.action.index.*;
import org.elasticsearch.action.search.*;
import org.elasticsearch.action.update.*;
import org.elasticsearch.common.unit.*;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.reindex.*;
import org.elasticsearch.search.*;
import org.elasticsearch.search.builder.*;
import org.elasticsearch.search.fetch.subphase.*;
import org.elasticsearch.search.sort.*;

import java.util.*;

/**
 * @Description EsRest工具类
 * @Author liuxi
 * @Date 2024/6/10
 **/
@Slf4j
public class EsRestUtil {

    /**
     * 新增文档
     *
     * @return boolean
     */
    public static boolean insertDoc(EsIndexInfo esIndexInfo, EsSourceData esSourceData) {
        try {
            IndexRequest indexRequest = new IndexRequest(esIndexInfo.getIndexName());
            indexRequest.source(esSourceData.getData());
            indexRequest.id(esSourceData.getDocId());
            EsRestClient.getClient(esIndexInfo.getClusterName()).index(indexRequest, EsRestClient.COMMON_OPTIONS);
            return true;
        } catch (Exception e) {
            log.error("insertDoc.exception:{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 更新文档
     *
     * @return boolean
     */
    public static boolean updateDoc(EsIndexInfo esIndexInfo, EsSourceData esSourceData) {
        try {
            UpdateRequest updateRequest = new UpdateRequest();
            updateRequest.index(esIndexInfo.getIndexName());
            updateRequest.id(esSourceData.getDocId());
            updateRequest.doc(esSourceData.getData());
            EsRestClient.getClient(esIndexInfo.getClusterName()).update(updateRequest, EsRestClient.COMMON_OPTIONS);
            return true;
        } catch (Exception e) {
            log.error("updateDoc.exception:{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 批量更新文档
     *
     * @return boolean
     */
    public static boolean batchUpdateDoc(EsIndexInfo esIndexInfo, List<EsSourceData> esSourceDataList) {
        try {
            boolean flag = false;
            BulkRequest bulkRequest = new BulkRequest();
            for (EsSourceData esSourceData : esSourceDataList) {
                String docId = esSourceData.getDocId();
                if (StringUtils.isNotBlank(docId)) {
                    UpdateRequest updateRequest = new UpdateRequest();
                    updateRequest.index(esIndexInfo.getIndexName());
                    updateRequest.id(esSourceData.getDocId());
                    updateRequest.doc(esSourceData.getData());
                    bulkRequest.add(updateRequest);
                    flag = true;
                }
            }
            if (flag) {
                BulkResponse bulk = EsRestClient.getClient(esIndexInfo.getClusterName())
                        .bulk(bulkRequest, EsRestClient.COMMON_OPTIONS);
                return !bulk.hasFailures();
            }

            return true;
        } catch (Exception e) {
            log.error("batchUpdateDoc.exception:{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 删除全部文档
     *
     * @return boolean
     */
    public static boolean deleteDoc(EsIndexInfo esIndexInfo) {
        try {
            DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(esIndexInfo.getIndexName());
            deleteByQueryRequest.setQuery(QueryBuilders.matchAllQuery());
            BulkByScrollResponse response = EsRestClient.getClient(esIndexInfo.getClusterName())
                    .deleteByQuery(deleteByQueryRequest, EsRestClient.COMMON_OPTIONS);
            long deleted = response.getDeleted();
            log.info("deleteDoc.size:{}", deleted);
            return true;
        } catch (Exception e) {
            log.error("deleteDoc.exception:{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 根据id删除文档
     *
     * @return boolean
     */
    public static boolean deleteDoc(EsIndexInfo esIndexInfo, String docId) {
        try {
            DeleteRequest deleteRequest = new DeleteRequest(esIndexInfo.getIndexName());
            deleteRequest.id(docId);
            DeleteResponse response = EsRestClient.getClient(esIndexInfo.getClusterName()).delete(deleteRequest,
                    EsRestClient.COMMON_OPTIONS);
            log.info("deleteDoc.response:{}", JSON.toJSONString(response));
            return true;
        } catch (Exception e) {
            log.error("deleteDoc.exception:{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 判断文档是否存在
     *
     * @return boolean
     */
    public static boolean isExistDocById(EsIndexInfo esIndexInfo, String docId) {
        try {
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);
            return EsRestClient.getClient(esIndexInfo.getClusterName()).exists(getRequest, EsRestClient.COMMON_OPTIONS);
        } catch (Exception e) {
            log.error("esIndexInfo.exception:{}", e.getMessage(), e);
        }
        return false;
    }

    /**
     * 根据文档id获取文档
     *
     * @return boolean
     */
    public static Map<String, Object> getDocById(EsIndexInfo esIndexInfo, String docId) {
        try {
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);
            GetResponse response = EsRestClient.getClient(esIndexInfo.getClusterName())
                    .get(getRequest, EsRestClient.COMMON_OPTIONS);
            return response.getSource();
        } catch (Exception e) {
            log.error("esIndexInfo.exception:{}", e.getMessage(), e);
        }
        return null;
    }

    /**
     * 根据文档id,字段获取文档
     *
     * @return boolean
     */
    public static Map<String, Object> getDocById(EsIndexInfo esIndexInfo, String docId, String[] fields) {
        try {
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);
            FetchSourceContext context = new FetchSourceContext(true, fields, null);
            getRequest.fetchSourceContext(context);
            GetResponse response = EsRestClient.getClient(esIndexInfo.getClusterName())
                    .get(getRequest, EsRestClient.COMMON_OPTIONS);
            return response.getSource();
        } catch (Exception e) {
            log.error("esIndexInfo.exception:{}", e.getMessage(), e);
        }
        return null;
    }

    /**
     * 搜索
     *
     * @return boolean
     */
    public static SearchResponse searchWithTermQuery(EsIndexInfo esIndexInfo, EsSearchRequest esSearchRequest) {
        try {
            BoolQueryBuilder bq = esSearchRequest.getBq();
            String[] fields = esSearchRequest.getFields();
            int from = esSearchRequest.getFrom();
            int size = esSearchRequest.getSize();
            Long minutes = esSearchRequest.getMinutes();
            Boolean needScroll = esSearchRequest.getNeedScroll();
            String sortName = esSearchRequest.getSortName();
            SortOrder sortOrder = esSearchRequest.getSortOrder();

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(bq);
            searchSourceBuilder.fetchSource(fields, null).from(from).size(size);

            if (Objects.nonNull(esSearchRequest.getHighlightBuilder())) {
                searchSourceBuilder.highlighter(esSearchRequest.getHighlightBuilder());
            }

            if (StringUtils.isNotBlank(sortName)) {
                searchSourceBuilder.sort(sortName);
            }

            if (Objects.isNull(sortOrder)) {
                sortOrder = SortOrder.DESC;
            }
            searchSourceBuilder.sort(new ScoreSortBuilder().order(sortOrder));

            SearchRequest searchRequest = new SearchRequest();
            searchRequest.searchType(SearchType.DEFAULT);
            searchRequest.indices(esIndexInfo.getIndexName());
            searchRequest.source(searchSourceBuilder);
            if (needScroll) {
                Scroll scroll = new Scroll(TimeValue.timeValueMillis(minutes));
                searchRequest.scroll(scroll);
            }
            return EsRestClient.getClient(esIndexInfo.getClusterName()).search(searchRequest, EsRestClient.COMMON_OPTIONS);
        } catch (Exception e) {
            log.error("searchWithTermQuery.exception:{}", e.getMessage(), e);
        }
        return null;
    }

}
